<template>
  <node-view-wrapper :id="node.attrs.id" class="toc-node-view">
    <div class="toc-container">
      <div class="toc-header">
        <p class="toc-head">目录</p>
        <el-button
          class="toc-refresh-btn"
          text
          size="small"
          @click="handleRefresh"
          title="更新目录"
        >
          <i class="i-ri-refresh-line"></i>
        </el-button>
      </div>
      <div class="toc-body">
        <div v-if="tocTreeData.length === 0" class="toc-empty">暂无标题</div>
        <div v-else class="toc-tree">
          <div
            v-for="(item, index) in tocTreeData"
            :key="item.id"
            class="toc-item"
            :class="[
              `toc-level-${item.level}`,
              {
                'toc-item-last': isLastChild(index, item.level),
                'toc-item-has-children': hasChildren(item.id),
              },
            ]"
          >
            <span
              v-if="hasChildren(item.id)"
              class="toc-expand-btn"
              :class="{ 'toc-expanded': isExpanded(item.id) }"
              @click.stop="toggleExpand(item.id)"
            >
              <i class="i-ri-arrow-right-s-line"></i>
            </span>
            <span v-else class="toc-expand-placeholder"></span>
            <span class="toc-text" @click="handleHeadingClick(item)">{{
              item.textContent
            }}</span>
          </div>
        </div>
      </div>
    </div>
  </node-view-wrapper>
</template>

<script setup lang="ts">
import { computed, inject, watch, ref, onMounted } from "vue";
import { NodeViewWrapper } from "@tiptap/vue-3";
import type { Editor } from "@tiptap/vue-3";
import type { Ref } from "vue";
import { TextSelection } from "@tiptap/pm/state";
import { ElButton, ElMessage } from "element-plus";

interface TocItem {
  id: string;
  textContent: string;
  level: number;
  originalLevel: number;
  children?: TocItem[];
  isExpanded?: boolean;
}

defineProps<{
  node: any;
  editor: Editor;
}>();

const editor = inject<Ref<Editor>>("editor");

// 监听 storage 中的目录数据
const tocContent = computed(() => {
  return editor?.value?.storage?.tableOfContents?.content || [];
});

// 展开状态管理
const expandedMap = ref<Map<string, boolean>>(new Map());

// 初始化展开状态，默认全部展开
const initExpandedState = (tree: TocItem[]) => {
  const traverse = (nodes: TocItem[]) => {
    for (const node of nodes) {
      if (!expandedMap.value.has(node.id)) {
        expandedMap.value.set(node.id, true); // 默认展开
      }
      if (node.children && node.children.length > 0) {
        traverse(node.children);
      }
    }
  };
  traverse(tree);
};

// 构建树形结构
const buildTocTree = (tocArray: TocItem[]): TocItem[] => {
  const root: TocItem[] = [];
  const stack: TocItem[] = [];

  for (const item of tocArray) {
    const node: TocItem = {
      id: item.id,
      textContent: item.textContent,
      level: item.originalLevel,
      originalLevel: item.originalLevel,
      children: [],
      isExpanded: expandedMap.value.get(item.id) ?? true,
    };

    // 找到当前节点的父节点（栈中级别小于当前节点的最后一个节点）
    while (
      stack.length > 0 &&
      stack[stack.length - 1].level >= item.originalLevel
    ) {
      stack.pop();
    }

    if (stack.length === 0) {
      root.push(node);
    } else {
      if (!stack[stack.length - 1].children) {
        stack[stack.length - 1].children = [];
      }
      stack[stack.length - 1].children!.push(node);
    }

    stack.push(node);
  }

  // 初始化展开状态
  initExpandedState(root);

  // 确保返回的树结构包含完整的 children 信息
  return root;
};

// 扁平化树形结构用于显示，根据展开状态决定是否包含子节点
const flattenTree = (tree: TocItem[]): TocItem[] => {
  const result: TocItem[] = [];
  const traverse = (nodes: TocItem[], level: number = 0) => {
    for (const node of nodes) {
      const isExpanded = expandedMap.value.get(node.id) ?? true;
      result.push({ ...node, level, isExpanded });
      // 只有展开时才遍历子节点
      if (isExpanded && node.children && node.children.length > 0) {
        traverse(node.children, level + 1);
      }
    }
  };
  traverse(tree);
  return result;
};

const tocTreeData = ref<TocItem[]>([]);

// 判断是否是同级最后一个节点
const isLastChild = (index: number, level: number): boolean => {
  // 如果是最后一项，肯定是最后一个
  if (index === tocTreeData.value.length - 1) {
    return true;
  }

  // 检查下一项的级别，如果级别小于等于当前级别，说明是最后一个
  const nextItem = tocTreeData.value[index + 1];
  if (!nextItem) {
    return true;
  }

  return nextItem.level <= level;
};

// 判断节点是否有子节点
const hasChildren = (id: string): boolean => {
  // 方法1：从原始树结构查找（更准确）
  const findNode = (nodes: TocItem[]): TocItem | null => {
    for (const node of nodes) {
      if (node.id === id) {
        return node;
      }
      if (node.children && node.children.length > 0) {
        const found = findNode(node.children);
        if (found) return found;
      }
    }
    return null;
  };

  // 优先从原始树查找
  if (originalTree.value && originalTree.value.length > 0) {
    const node = findNode(originalTree.value);
    if (node && node.children && node.children.length > 0) {
      return true;
    }
  }

  // 方法2：如果原始树还没有数据，通过扁平化列表判断（备用方案）
  // 查找当前项的索引
  const currentIndex = tocTreeData.value.findIndex((item) => item.id === id);
  if (currentIndex === -1) {
    return false;
  }

  // 如果是最后一项，肯定没有子节点
  if (currentIndex === tocTreeData.value.length - 1) {
    return false;
  }

  const currentItem = tocTreeData.value[currentIndex];
  if (!currentItem) return false;

  // 查找下一项
  const nextItem = tocTreeData.value[currentIndex + 1];
  if (!nextItem) return false;

  // 如果下一项的 originalLevel 大于当前项的 originalLevel，说明有子节点
  // 注意：这里需要比较 originalLevel，因为 level 是扁平化后的层级
  return nextItem.originalLevel > currentItem.originalLevel;
};

// 获取原始树结构（从 buildTocTree 的结果）
const originalTree = ref<TocItem[]>([]);

// 检查节点是否展开
const isExpanded = (id: string): boolean => {
  return expandedMap.value.get(id) ?? true;
};

// 切换展开/收缩状态
const toggleExpand = (id: string) => {
  const currentState = expandedMap.value.get(id) ?? true;
  expandedMap.value.set(id, !currentState);

  // 重新扁平化树（不需要重新构建，因为原始树结构不变）
  if (originalTree.value.length > 0) {
    tocTreeData.value = flattenTree(originalTree.value);
  } else {
    // 如果原始树为空，重新构建
    const tree = buildTocTree(tocContent.value);
    originalTree.value = JSON.parse(JSON.stringify(tree)); // 深拷贝
    tocTreeData.value = flattenTree(tree);
  }
};

// 处理刷新目录
const handleRefresh = () => {
  if (!editor?.value) return;

  try {
    editor.value.chain().focus().updateTableOfContents().run();

    // 检查更新后的结果
    setTimeout(() => {
      const content = editor.value?.storage.tableOfContents?.content || [];
      if (content.length > 0) {
        ElMessage.success(`目录已更新，共 ${content.length} 个标题`);
      } else {
        ElMessage.warning("未找到标题，请确保文档中有标题内容");
      }
    }, 100);
  } catch (error) {
    ElMessage.error("更新目录失败");
  }
};

watch(
  tocContent,
  (toc: TocItem[]) => {
    if (toc && toc.length > 0) {
      const tree = buildTocTree(toc);
      // 深拷贝保存原始树，确保 children 信息完整
      originalTree.value = JSON.parse(JSON.stringify(tree));
      tocTreeData.value = flattenTree(tree);
    } else {
      tocTreeData.value = [];
      originalTree.value = [];
    }
  },
  { immediate: true, deep: true }
);

// 组件挂载时，如果目录为空，尝试更新一次
onMounted(() => {
  if (!editor?.value) return;

  // 延迟一下，确保 storage 已经初始化
  setTimeout(() => {
    const content = editor.value.storage.tableOfContents?.content || [];
    if (content.length === 0) {
      // 手动触发更新
      handleRefresh();
    }
  }, 200);
});

// 处理标题点击
const handleHeadingClick = (item: TocItem) => {
  if (!editor?.value) return;

  const editorView = editor.value.view;

  // 通过遍历文档查找标题
  let targetPos = -1;
  editorView.state.doc.descendants((node, pos) => {
    if (node.type.name === "heading") {
      const level = node.attrs.level as number;
      const textContent = node.textContent.trim();

      // 匹配标题文本和级别
      if (
        textContent === item.textContent &&
        level === item.originalLevel &&
        targetPos === -1
      ) {
        targetPos = pos;
        return false; // 停止遍历
      }
    }
  });

  if (targetPos === -1) return;

  // 设置选中状态并滚动
  try {
    const { tr } = editorView.state;
    const resolvedPos = tr.doc.resolve(targetPos);
    tr.setSelection(new TextSelection(resolvedPos));
    editorView.dispatch(tr);
    editorView.focus();

    // 等待 DOM 更新后滚动
    setTimeout(() => {
      // 查找对应的 DOM 元素
      const domAtPos = editorView.domAtPos(targetPos);
      const nodeElement =
        domAtPos.node.nodeType === 3
          ? domAtPos.node.parentElement
          : (domAtPos.node as Element);

      if (!nodeElement) return;

      // 查找滚动容器（尝试多个选择器）
      const scrollContainer =
        (document.querySelector(".editor-page-content") as HTMLElement) ||
        (document.querySelector(".editor-main-content") as HTMLElement) ||
        (document.querySelector(".editor-main") as HTMLElement);

      if (scrollContainer && nodeElement) {
        const rect = nodeElement.getBoundingClientRect();
        const containerRect = scrollContainer.getBoundingClientRect();
        const scrollTop =
          scrollContainer.scrollTop + rect.top - containerRect.top - 100;

        scrollContainer.scrollTo({
          top: Math.max(0, scrollTop),
          behavior: "smooth",
        });
      } else {
        // 如果找不到容器，使用全局滚动
        nodeElement.scrollIntoView({
          behavior: "smooth",
          block: "center",
        });
      }
    }, 50);
  } catch (error) {
    // 静默处理错误
  }
};
</script>

<style scoped lang="scss">
.toc-node-view {
  margin: 16px 0;
}

.toc-container {
  padding: 44px 24px 24px 24px;
  position: relative;
  outline: 1px solid var(--editor-border-color, #e5e7eb);
  border-radius: var(--editor-radius-medium, 8px);
  background-color: var(--editor-color-white, #ffffff);
  width: 100%;

  .toc-header {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 24px;
  }

  .toc-head {
    font-weight: 600;
    margin: 0;
    padding: 8px 12px;
    border-bottom-left-radius: 4px;
    border-bottom-right-radius: 4px;
    font-size: 16px;
    background: rgba(0, 0, 0, 0.05);
    color: var(--editor-primary-color, #1890ff);
  }

  .toc-refresh-btn {
    padding: 4px 8px;
    color: var(--editor-text-color-secondary, #8c8c8c);

    &:hover {
      color: var(--editor-primary-color, #1890ff);
      background-color: var(--editor-button-hover-background, #f5f5f5);
    }
  }

  .toc-body {
    .toc-empty {
      padding: 20px;
      text-align: center;
      color: var(--editor-text-color-secondary, #8c8c8c);
      font-size: 14px;
    }

    .toc-tree {
      position: relative;

      .toc-item {
        position: relative;
        padding: 6px 8px;
        cursor: pointer;
        border-radius: 4px;
        transition: all 0.2s;
        margin-bottom: 2px;
        font-size: 14px;
        line-height: 1.5;
        color: var(--editor-text-color, #333);
        display: flex;
        align-items: center;
        min-height: 24px;

        // 连接线样式
        &::before {
          content: "";
          position: absolute;
          left: 0;
          top: 0;
          bottom: 0;
          width: 1px;
          background-color: var(--editor-border-color, #e5e7eb);
        }

        // 水平连接线
        &::after {
          content: "";
          position: absolute;
          left: 0;
          top: 50%;
          width: 20px;
          height: 1px;
          background-color: var(--editor-border-color, #e5e7eb);
        }

        // 最后一项不显示向下的垂直线
        &.toc-item-last::before {
          bottom: 50%;
        }

        // 第一项不显示向上的垂直线
        &:first-child::before {
          top: 50%;
        }

        // 只有一项时，不显示垂直线
        &:first-child.toc-item-last::before {
          display: none;
        }

        &:hover {
          background-color: var(--editor-button-hover-background, #f5f5f5);
          color: var(--editor-primary-color, #1890ff);
        }

        .toc-expand-btn {
          display: inline-flex;
          align-items: center;
          justify-content: center;
          width: 20px;
          height: 20px;
          margin-right: 4px;
          cursor: pointer;
          transition: all 0.2s;
          color: var(--editor-text-color-secondary, #8c8c8c);
          flex-shrink: 0;
          border-radius: 2px;
          position: relative;
          z-index: 1;

          i {
            font-size: 16px;
            line-height: 1;
            display: inline-block;
            width: 16px;
            height: 16px;
            transition: transform 0.2s;
          }

          &.toc-expanded {
            i {
              transform: rotate(90deg);
            }
          }

          &:hover {
            color: var(--editor-primary-color, #1890ff);
            background-color: var(--editor-button-hover-background, #f5f5f5);
          }
        }

        .toc-expand-placeholder {
          display: inline-block;
          width: 20px;
          height: 20px;
          margin-right: 4px;
          flex-shrink: 0;
        }

        .toc-text {
          display: inline-block;
          flex: 1;
          cursor: pointer;
        }

        // 不同级别的缩进和连接线位置
        // 基础缩进：每级 16px
        &.toc-level-0 {
          padding-left: 8px;
          font-weight: 600;

          &::before,
          &::after {
            display: none;
          }
        }

        &.toc-level-1 {
          padding-left: 24px;
          font-weight: 600;

          &::before {
            left: 20px;
          }

          &::after {
            left: 20px;
          }
        }

        &.toc-level-2 {
          padding-left: 40px;

          &::before {
            left: 36px;
          }

          &::after {
            left: 36px;
          }
        }

        &.toc-level-3 {
          padding-left: 56px;

          &::before {
            left: 52px;
          }

          &::after {
            left: 52px;
          }
        }

        &.toc-level-4 {
          padding-left: 72px;

          &::before {
            left: 68px;
          }

          &::after {
            left: 68px;
          }
        }

        &.toc-level-5 {
          padding-left: 88px;

          &::before {
            left: 84px;
          }

          &::after {
            left: 84px;
          }
        }

        &.toc-level-6 {
          padding-left: 104px;

          &::before {
            left: 100px;
          }

          &::after {
            left: 100px;
          }
        }
      }
    }
  }
}

// 暗黑模式支持
@media (prefers-color-scheme: dark) {
  .toc-container {
    background-color: var(--editor-color-dark-bg, #1f1f1f);
    outline-color: var(--editor-border-color-dark, #3a3a3a);

    .toc-head {
      background: rgba(255, 255, 255, 0.1);
      color: var(--editor-primary-color, #1890ff);
    }

    .toc-body {
      .toc-item {
        color: var(--editor-text-color-dark, #e5e5e5);

        &::before,
        &::after {
          background-color: var(--editor-border-color-dark, #3a3a3a);
        }

        &:hover {
          background-color: var(--editor-button-hover-background-dark, #2a2a2a);
        }
      }
    }
  }
}
</style>
